本文將會講解如何利用 DevTools 找出瀏覽器繪製頁面的效能瓶頸,並利用 GPU 和瀏覽器繪製頁面的機制來優化動畫效能,閱讀本文前建議先理解瀏覽器繪製頁面的流程,可以參考 Performance - How Rendering Works。
網頁中的動畫出現效能問題時,光看 Performance 面板中的長長的綠色區塊很難找出造成瓶頸的原因,一般會搭配 DevTools 中的其他面板來觀察繪製過程和 Layer 資訊,它們分成三個部分:
有了這些工具,就能開始分析頁面造成效能瓶頸的原因並針對該部分進行優化。
使用 Paint Profiler 之前,需要開啟 Performance 設定的 Enable advanced paint instrumentation 選項,才能在 Paint 的過程中紀錄每個步驟:
開啟 Paint Profiler 後,隨意進入一個網頁,重新整理錄製效能資訊,點擊 Paint 區塊會發現詳細資訊面板多了一個 Paint Profiler
分頁,裡面由三個部分組成:
時間線中柱體的長度代表花費的時間,可以在時間線中拖曳一小區段,來看看特定時間內的繪製指令和對應的結果。
指令列表中很明顯可以看出 drawTextBlob
用來繪製文字,展開能看到座標、顏色等等屬性,還有 Canvas 中很常見的 save
、restore
、translate
指令。
在 More tools 中可以看到 Layers 面板,點擊後會顯示目前的 Layer 資訊,左側可以看到頁面中總共有哪些 Layers,點擊 Layers 列表或是中間視覺化區域內的 Layer 可以看到詳細資訊,包括 Layer 的大小、產生的原因、記憶體用量。
另外可以用上方的工具列來把玩視覺化的 Layers,畫面過於混亂時可以關掉 Paints 選項只顯示所有 Layers 的邊界。
如果有打開 Enable advanced paint instrumentation 選項,點擊 Frames 中任意一個 Frame 會看到 Layers 分頁,介面和剛剛說明的 Layers 面板相同,用來觀察特定一幀的 Layers 資訊,也可以避免畫面大量動畫讓 Layers 面板跑不動的問題。
透過 Rendering Tab 能夠最快速的看出 Paint 的問題,按下 ESC 展開 Drawer,選單中可以找到 Rendering Tab,其中和 Paint 最相關的選項有:
為什麼拖曳視窗的時候視窗沒有重繪?
顯示頁面重繪的區域,通常綠色的框框越多、越大,就需要花越多時間繪製,如果發現一塊幾乎沒有變化的區域不斷被重繪,可以考慮把該區塊獨立為一個 Layer。
Paint flashing 只能看出重繪的區域,Layer borders 則會顯示 Layer 的邊界,被獨立出來的 Layer 會以橘色框線標示。
藍綠色的框線代表 Tile,一個 Layer 會再被切分為多個 Tiles 來加速繪製,不過怎麼切分就只能交給瀏覽器自己決定了。
關於 Tile 和 Raster 在 Performance - How Rendering Works 中皆有介紹。
打開範例網站後,會看到一大堆方塊,按下 Animate 方塊會開始轉圈,會發現頁面卡卡的,此時按下 Isolate 會發現動畫變順了。(若原本就很順就多開幾個分頁)
不知道為什麼?把剛才提到的工具拿來試試吧!
左半邊的 FPS 平均只有 20 ,下方有一大串代表繪製的綠色方塊,GPU 幾乎沒有休息;右半邊獨立 Layer 後 FPS 幾乎維持在 60
原本只有一片平坦的 Layer,獨立 Layer 後長出一條 Layer 龍
獨立 Layer 優化 VS 瘋狂重繪
原本 VS 獨立 Layer
原本 Demo 頁面中的方塊是透過 transform: translate();
來轉圈,點擊 Isolate 後會改為 transform: translate3d();
,效果和 transform: translateZ();
相同,會把該元素獨立到新的 Layer,原本不斷重繪整個畫面,變成稍稍移動 Layers 再進行合成,完全不用繪製。
此外在 CSS 的 .box
加入一條 will-change: transform;
也會把方塊獨立到新的 Layer。
http://udacity.github.io/60fps/lesson6/willChange/index.html
https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference
發現個錯字Canvas 中很常見的 save、resotre、translate
resotre -> restore
已修正 :D